/**
 * @p.md
 * 
 * 本地身份查找服务
 * 在单机环境下提供Actor身份查找功能
 */
import { PID } from '../../actor/pid';
import { Cluster } from '../cluster';
import { ClusterIdentity } from '../clusterIdentity';
import { 
  IdentityLookup, 
  LookupResult, 
  LookupStatus 
} from '../identityLookup';
import { Member, MemberStatus } from '../clusterConfig';
import { ProcessRegistry } from '../../actor/processRegistry';
import { GrainRegistry } from '../grain';

/**
 * 本地身份查找配置
 */
export interface LocalIdentityLookupConfig {
  /**
   * 默认查找超时(毫秒)
   */
  defaultLookupTimeout?: number;
  
  /**
   * 是否启用缓存
   */
  enableCache?: boolean;
  
  /**
   * 缓存过期时间(毫秒)
   */
  cacheExpiration?: number;
}

/**
 * 默认本地身份查找配置
 */
export const DefaultLocalIdentityLookupConfig: LocalIdentityLookupConfig = {
  defaultLookupTimeout: 5000,
  enableCache: true,
  cacheExpiration: 30000 // 30秒
};

/**
 * Actor注册项
 */
interface ActorRegistration {
  /**
   * Actor PID
   */
  pid: PID;
  
  /**
   * 身份
   */
  clusterIdentity: ClusterIdentity;
  
  /**
   * 所在节点ID
   */
  nodeId: string;
  
  /**
   * 注册时间
   */
  registeredAt: number;
}

/**
 * 缓存项
 */
interface CacheEntry {
  /**
   * 查找结果
   */
  result: LookupResult;
  
  /**
   * 过期时间
   */
  expiresAt: number;
}

/**
 * 本地身份查找服务
 * 用于在本地集群中查找和建立Actor
 */
export class LocalIdentityLookup implements IdentityLookup {
  /**
   * 集群引用
   */
  private cluster: Cluster | null = null;
  
  /**
   * Actor注册表
   */
  private actorRegistry: Map<string, ActorRegistration> = new Map();
  
  /**
   * 查找结果缓存
   */
  private lookupCache: Map<string, CacheEntry> = new Map();
  
  /**
   * 构造函数
   * @param config 配置
   */
  constructor(private config: LocalIdentityLookupConfig = DefaultLocalIdentityLookupConfig) {}

  /**
   * 初始化
   * @param cluster 集群引用
   */
  async init(cluster: Cluster): Promise<void> {
    this.cluster = cluster;
    
    // 定期清理过期缓存
    if (this.config.enableCache) {
      setInterval(() => this.cleanExpiredCache(), 
        Math.min(this.config.cacheExpiration || 30000, 30000));
    }
  }

  /**
   * 查找Actor
   * @param clusterIdentity 集群身份
   * @param timeout 超时时间
   */
  async lookup(
    clusterIdentity: ClusterIdentity,
    timeout?: number
  ): Promise<LookupResult> {
    if (!this.cluster) {
      return {
        status: LookupStatus.Error,
        error: '身份查找服务尚未初始化'
      };
    }
    
    const identityString = clusterIdentity.toString();
    
    // 检查缓存
    if (this.config.enableCache) {
      const cachedResult = this.lookupCache.get(identityString);
      if (cachedResult && cachedResult.expiresAt > Date.now()) {
        return cachedResult.result;
      }
      
      // 移除过期缓存
      if (cachedResult) {
        this.lookupCache.delete(identityString);
      }
    }
    
    // 检查本地注册表
    const registration = this.actorRegistry.get(identityString);
    if (registration) {
      const result: LookupResult = {
        status: LookupStatus.Success,
        pid: registration.pid
      };
      
      // 更新缓存
      this.updateCache(identityString, result);
      return result;
    }
    
    // 在集群中寻找可用节点
    const memberList = this.cluster.getMemberList();
    const aliveMembers = memberList.getAliveMembers();
    
    if (aliveMembers.length === 0) {
      return {
        status: LookupStatus.Unavailable,
        error: '没有可用的集群节点'
      };
    }
    
    // 选择一个节点来激活Actor
    // 在本地实现中，我们总是使用当前节点
    const localMember = memberList.getLocalMember();
    if (!localMember) {
      return {
        status: LookupStatus.Error,
        error: '无法获取本地节点信息'
      };
    }
    
    // 在本地节点上激活Actor
    const activationResult = await this.establishActor(
      clusterIdentity,
      localMember.address
    );
    
    // 更新缓存
    if (activationResult.status === LookupStatus.Success) {
      this.updateCache(identityString, activationResult);
    }
    
    return activationResult;
  }

  /**
   * 创建Actor
   * @param clusterIdentity 集群身份
   * @param activatorAddress 激活器地址
   */
  async establishActor(
    clusterIdentity: ClusterIdentity,
    activatorAddress: string
  ): Promise<LookupResult> {
    if (!this.cluster) {
      throw new Error('Cluster not initialized');
    }

    try {
      const actorSystem = this.cluster.getActorSystem();
      const nodeId = this.cluster.getNodeId();
      console.log(`[LocalIdentityLookup] 开始在节点 ${nodeId} (${activatorAddress}) 上创建Actor: ${clusterIdentity.toString()}`);

      // 获取 Props
      const registry = GrainRegistry.getInstance();
      if (!registry.hasGrain(clusterIdentity.kind)) {
        throw new Error(`未注册的Grain类型: ${clusterIdentity.kind}`);
      }

      const props = registry.getGrainProps(clusterIdentity.kind, clusterIdentity.identity);
      if (!props) {
        throw new Error(`无法创建Grain Props: ${clusterIdentity.toString()}`);
      }

      // 生成唯一的 Actor ID
      const actorId = `${clusterIdentity.identity}$${clusterIdentity.kind}`;
      console.log(`[LocalIdentityLookup] 使用ID创建Actor: ${actorId} at ${activatorAddress}`);

      // 获取当前节点的有效网络地址
      // 使用当前节点的实际地址，而不是传入的activatorAddress
      const nodeAddress = this.cluster.getConfig().nodeAddress;
      console.log(`[LocalIdentityLookup] 将使用当前节点地址: ${nodeAddress} 创建Actor`);
      
      // 在创建 Actor 之前注册当前网络地址到进程注册表
      const processRegistry = ProcessRegistry.getInstance();
      if (typeof processRegistry._setAddress === 'function') {
        console.log(`[LocalIdentityLookup] 更新进程注册表地址: ${nodeAddress}`);
        (processRegistry as any)._setAddress(nodeAddress);
      } else {
        console.log(`[LocalIdentityLookup] 警告: 无法更新进程注册表地址，将使用默认地址`);
      }
      
      // 创建 Actor 并获取 PID
      const pid = actorSystem.root.spawnNamed(props, actorId);
      
      console.log(`[LocalIdentityLookup] 创建Actor成功: ${pid.toString()}`);
      console.log(`[LocalIdentityLookup] Actor路径: address=${pid.address}, id=${pid.id}`);

      // 验证 PID 是否已注册到 ProcessRegistry
      const process = processRegistry.get(pid);
      console.log(`[LocalIdentityLookup] 验证PID注册: ${process ? '成功' : '失败'}`);

      // 输出所有注册的进程
      console.log(`[LocalIdentityLookup] 当前进程注册表状态:`);
      if ('getAllProcesses' in processRegistry) {
        const processes = (processRegistry as any).getAllProcesses();
        processes.forEach((p: string) => console.log(`  - ${p}`));
      }

      // 注册到本地表
      this.actorRegistry.set(clusterIdentity.toString(), {
        pid,
        clusterIdentity,
        nodeId,
        registeredAt: Date.now()
      });

      return {
        status: LookupStatus.Success,
        pid
      };
    } catch (error) {
      console.error(`[LocalIdentityLookup] 创建Actor失败:`, error);
      return {
        status: LookupStatus.Error,
        error: `创建Actor失败: ${(error as Error).message}`
      };
    }
  }

  /**
   * 关闭服务
   */
  async shutdown(): Promise<void> {
    // 清空注册表和缓存
    this.actorRegistry.clear();
    this.lookupCache.clear();
    this.cluster = null;
  }

  /**
   * 更新缓存
   * @param key 缓存键
   * @param result 结果
   */
  private updateCache(key: string, result: LookupResult): void {
    if (!this.config.enableCache) {
      return;
    }
    
    const expiresAt = Date.now() + (this.config.cacheExpiration || 30000);
    this.lookupCache.set(key, {
      result,
      expiresAt
    });
  }

  /**
   * 清理过期缓存
   */
  private cleanExpiredCache(): void {
    const now = Date.now();
    for (const [key, entry] of this.lookupCache.entries()) {
      if (entry.expiresAt <= now) {
        this.lookupCache.delete(key);
      }
    }
  }
} 